/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * TrainingBook
 * Copyright (C) Arnaud Duval 2010 <arnaud.duval@gmail.com>
 * 
 * Projects is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Projects is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <t-bmain-window.hpp>
#include <iostream>
#include <activity-edit-dialog.hpp>
#include <user-day-edit-dialog.hpp>
#include <sstream>
#include <config.hpp>
#include <track-view-dialog.hpp>
#include <list>
#include <activity-analysis-dialog.hpp>
#include <tcx-import-dialog.hpp>
#include <filesystem-utils.hpp>
#include <unistd.h>


///@brief Default Constructor
TBmainWindow::TBmainWindow() : Gtk::Window()
{
    ///READING CONFIGURATION
    std::string userDirPath;
    if(TRAININGBOOK_OS == "Windows")
        userDirPath = std::string(getenv(TRAININGBOOK_USER_DIR_DRIVE_ENV_VAR)) + getenv(TRAININGBOOK_USER_DIR_ENV_VAR);
    else
        userDirPath = std::string(getenv(TRAININGBOOK_USER_DIR_ENV_VAR));
    
    if(!DirExists(userDirPath + TRAININGBOOK_FILE_SEPARATOR + ".trainingbook"))
    {
        CreateDir(userDirPath + TRAININGBOOK_FILE_SEPARATOR + ".trainingbook");
    }

    ///@warning The configuration file should be located where the program is launched (not in the exe directory)
    application.ReadConfigurationFile(userDirPath + TRAININGBOOK_FILE_SEPARATOR + ".trainingbook" + TRAININGBOOK_FILE_SEPARATOR + "config.txt");
    //application.PrintConfig();

    
    currentBook.SetAppli(&application);
    aNotebook.SetActivity(&eActivity);
    
    

    
    
    // Set the title of the window
    set_title(std::string("Training Book ")+ TRAININGBOOK_VERSION);
    
    // Set the default size of the window
    set_default_size(800,600);
    // Set the border width of the window
    set_border_width(0);
    // Add the main vertical box to the window
    add(mainVBox);

    // Configure the menu
    ConfigureMenu();

    //Set the status bar affected to the osm map area
    //mapArea.SetStatusBar(&statusBar);

    // Add widgets to the main vertical box
    //mainVBox.pack_start(activityListSW, Gtk::PACK_EXPAND_WIDGET);
    //mainVBox.pack_start(mapArea, Gtk::PACK_EXPAND_WIDGET);
    mainVBox.pack_start(mainVPaned, Gtk::PACK_EXPAND_WIDGET);
    mainVBox.pack_end(statusBar, Gtk::PACK_SHRINK);

    //Add widgets to the vertical scalable box
    mainVPaned.add1(activityListSW);
    //mainVPaned.add2(mapArea);
    mainVPaned.add2(aNotebook);
    activityListSW.set_size_request (800, 300);

    //Add ListView to the Scrolled window
    activityListSW.add(activityListTV);
    //Only show scrollbar when needed
    activityListSW.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    ///@todo Settings of the popup menu could be made in a separated function
    //Initialization of the popup menu
    Gtk::MenuItem* item = Gtk::manage(new Gtk::MenuItem("Editer"));
    item->signal_activate().connect(sigc::mem_fun(*this, &TBmainWindow::on_activity_edit));
    popupMenu.append(*item);
    item = Gtk::manage(new Gtk::MenuItem("Supprimer"));
    item->signal_activate().connect(sigc::mem_fun(*this, &TBmainWindow::on_activity_delete));
    popupMenu.append(*item);
    item = Gtk::manage(new Gtk::MenuItem("Visualiser la trace"));
    item->signal_activate().connect(sigc::mem_fun(*this, &TBmainWindow::on_activity_view_track));
    popupMenu.append(*item);
    item = Gtk::manage(new Gtk::MenuItem("Analyser l'activité"));
    item->signal_activate().connect(sigc::mem_fun(*this, &TBmainWindow::on_activity_analyse));
    popupMenu.append(*item);
    popupMenu.show_all();

    popupMenu.accelerate(*this);





    //Zone de test
    activityListTV.signal_button_press_event().connect(sigc::mem_fun(*this,
                 &TBmainWindow::on_treeview_click), false);
    //Fin de la zone de test
    statusBar.signal_text_pushed().connect(sigc::mem_fun(*this, &TBmainWindow::Refresh), false);



    // Read default file
    //std::string defaultFilePath = "/home/arnaud/trainingbook.xml";
    //std::string defaultFilePath = std::string(TRAININGBOOK_USER_DIR)+"/trainingbook.xml";
    std::string defaultFilePath = application.GetParameter("TRAININGBOOK_DIR")+TRAININGBOOK_FILE_SEPARATOR+application.GetParameter("TRAININGBOOK_DEFAULT_FILE_NAME");
    if(currentBook.ReadXML(defaultFilePath))
    {
        std::cout << "The default trainingbook file exists.\n";
        currentFile = defaultFilePath;
        update_treeview();
        set_title("Training Book "+softVersion + " : " + currentFile);
    }
    else
    {
        std::cerr << "Default file does not exist\n";
    }
    
    //Setting the map area   
    ///@warning Tiles cache must be set before the tiles repository
    //mapArea.SetTilesCache(application.GetParameter("TILES_CACHE"));
    //mapArea.SetTilesRepository(application.GetParameter("TILES_REPOSITORY"));


    
    show_all_children();
    statusBar.push("Prêt");
}

TBmainWindow::~TBmainWindow()
{

}

void TBmainWindow::on_button_quit()
{
    hide(); //hide will cause main::run() to exit
}

///@brief Click on the open file button
void TBmainWindow::on_menu_file_open()
{
    Gtk::FileChooserDialog dialog("Ouvrir..",
                                  Gtk::FILE_CHOOSER_ACTION_OPEN);
    dialog.set_transient_for(*this);

    //Add button to the dialog
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

    //Set the initial folder
    dialog.set_current_folder(Glib::get_home_dir());
    
    //Add filters for file type
    Gtk::FileFilter filter_xml;
    filter_xml.set_name("Fichier XML");
    filter_xml.add_mime_type("text/xml");
    dialog.add_filter(filter_xml);
    
    //Show the dialog
    int result = dialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            currentBook.ReadXML(dialog.get_filename());
            currentFile = dialog.get_filename();
            update_treeview();
            set_title("Training Book "+softVersion + " : " + currentFile);
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}


void TBmainWindow::on_menu_file_save()
{
    statusBar.push("Sauvegarde en cours...");
    std::ifstream file(currentFile.c_str());
    if(!file.fail())
    {
        file.close();
        currentBook.WriteXML(currentFile);
    }
    else
        on_menu_file_save_as();
    statusBar.push("Prêt");
}

///@brief Click on save as button
void TBmainWindow::on_menu_file_save_as()
{
    // Set the file saving dialog
    Gtk::FileChooserDialog dialog(*this, "Enregistrer sous...",
                                  Gtk::FILE_CHOOSER_ACTION_SAVE);
    // The dialog will ask a confirmation if file to write already exists
    dialog.set_do_overwrite_confirmation();
    // Set the initial folder
    dialog.set_current_folder(Glib::get_home_dir());
    // Add buttons
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

    // Show the dialog
    int result = dialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            statusBar.push("Sauvegarde en cours...");
            currentBook.WriteXML(dialog.get_filename());
            statusBar.push("Prêt");
            currentFile = dialog.get_filename();
            set_title("Training Book "+softVersion + " : " + currentFile);
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}

void TBmainWindow::on_menu_new_activity()
{
    // Set the activity edition dialog box
    ActivityEditDialog newActivityDialog("Nouvelle activité", this,
                                         currentBook.GetActivityTypes());
    // New activity date is set to the last date of the training book
    newActivityDialog.SetDate(currentBook.GetLastActivityDate());
    int result = newActivityDialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            newActivityDialog.UpdateActivity();
            std::cout << "I can't add the ativity. ActivityEditDialog should be improved to manage full activity (not only activity header)\n";
            //currentBook.AddActivity(newActivityDialog.GetActivity());
            update_treeview();
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}

///@brief Click on the new user day button
void TBmainWindow::on_menu_new_user_day()
{
    UserDayEditDialog newUserDayDialog("Nouvelle journée", this, currentBook.GetLastUserDay());
    newUserDayDialog.SetDate(currentBook.GetLastUserDayDate());
    int result = newUserDayDialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            newUserDayDialog.UpdateUserDay();
            //currentBook.AddUserDay(newUserDayDialog.GetUserDay());
            std::cout << newUserDayDialog.GetUserDay() << "\n";
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}

///@brief Update the tree view with value from the training book
void TBmainWindow::update_treeview()
{
    activityListTV.Clear();
    std::list<ActivityHeader>::iterator lit(currentBook.GetActivities().begin()), lend(currentBook.GetActivities().end());
    for(; lit != lend ; ++lit)
    {
        activityListTV.AddActivity(*lit);
    }
}

///@brief Action when clicking on the treeview
bool TBmainWindow::on_treeview_click(GdkEventButton* event)
{
    if((event->type == GDK_2BUTTON_PRESS)&&(event->button == 1))
    {
        if(activityListTV.LineSelected())
            on_activity_edit();
        return true;
    }
    else if((event->type == GDK_BUTTON_PRESS)&&(event->button == 3))
    {
        popupMenu.popup(event->button, event->time);
        return false;
    }
    else
        return false;
}

///@brief Edit the selected activity in the TreeView
void TBmainWindow::on_activity_edit()
{
    if(aNotebook.HaveModification())
    {
        Gtk::MessageDialog dialog(*this, 
                                  "L'activité a été modifiée, voulez-vous sauvegarder ?",
                                  false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
        
        
        
        dialog.set_title(this->get_title());
        dialog.set_secondary_text("Si vous répondez Non, les modifications effectuées seront perdues.");
        
        int result = dialog.run();
        if(result == Gtk::RESPONSE_YES) 
        {
            eActivity.GetHistory().WriteHistoryFile(eActivity.GetHeader().GetId(), 
                                                    application.GetParameter("TRAININGBOOK_DIR"));
            ///@warning This won't work if the activity id has been modified
            currentBook.UpdateActivity(eActivity.GetHeader());
            currentBook.WriteXML(currentFile);
            ///@brief Modifications have been saved
            aNotebook.SetNoModif();
            
        }
        else if(result == Gtk::RESPONSE_NO) 
        {
            ///@brief Modifications have been lost
            aNotebook.SetNoModif();
        }
    }
    
    if(!aNotebook.HaveModification())
    {
        std::string id = activityListTV.GetId();
        eActivity.SetHeader(currentBook.GetActivityById(id));
        ActivityHistory history;
        history.ReadHistoryFile(eActivity.GetHeader().GetId(), application.GetParameter("TRAININGBOOK_DIR"));
        eActivity.SetHistory(history);
        std::cout << "On a clique sur l'activite : " << eActivity.GetDateTime() << "\n";    

        aNotebook.Refresh();

    }
    
    
    





    /*// Get the date and time of the selected activity in the treeview
    DateTime id = activityListTV.GetDate();
    // Get the activity corresponding to the date
    ActivityHeader toEdit = currentBook.GetActivityByDate(id);

    // Set the dialog to edot the activity
    ActivityEditDialog newActivityDialog("Édition", this,
                                         currentBook.GetActivityTypes());
    newActivityDialog.SetActivity(toEdit);
    int result = newActivityDialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            newActivityDialog.UpdateActivity();
            std::cout << "ActivityEditDialog should be improve. I can't modify this activity\n";
            //currentBook.ModifyActivityByDate(id, newActivityDialog.GetActivity());
            update_treeview();
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {   
            break;
        }
    }*/
}

///@brief Delete the selected activity in the TreeView
void TBmainWindow::on_activity_delete()
{
    DateTime id = activityListTV.GetDate();
    currentBook.DeleteActivityByDate(id);
    update_treeview();
}

///@brief click on the preferences menu button
void TBmainWindow::on_prefs_click()
{
    PreferencesDialog dialog(this,
                             currentBook.GetActivityTypes(),
                             currentBook.GetOsmTilesRepository());
    int result = dialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            currentBook.SetActivityTypes(dialog.GetActivityTypes());
            currentBook.SetOsmTilesRepository(dialog.GetOsmTilesRepository());
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}

///@brief Click on the About button
void TBmainWindow::on_about_click()
{
    Gtk::AboutDialog dialog;
    dialog.set_program_name("TrainingBook");
    dialog.set_version(softVersion);
    dialog.set_copyright("© 2010");
    dialog.set_comments("TrainingBook est un logiciel de gestion de carnet d'entrainement à destination du sportif");
    dialog.set_license("GNU/GPLv3");
    dialog.set_website("http://arnoduval.free.fr");
    dialog.set_website_label("TrainingBook");
    //dialog.set_logo(Gdk::PixBuf::create_from_file("gtk.png"));
    std::list<std::string> listeAuteurs;
    listeAuteurs.push_back("Arnaud Duval");
    dialog.set_authors(listeAuteurs);
    dialog.run();
}

///@brief View the track of the selected activity
void TBmainWindow::on_activity_view_track()
{
    ///@warning This function should be rewritten
    /*DateTime id = activityListTV.GetDate();
    Activity toSee = currentBook.GetActivityByDate(id);
    TrackViewDialog dialog(this, toSee.GetTrack());
    int result = dialog.run();*/
}

///@brief Analyse the selected activity
void TBmainWindow::on_activity_analyse()
{
    DateTime id = activityListTV.GetDate();
    //Activity toSee = currentBook.GetActivityByDate(id);
    //ActivityAnalysisDialog dialog(toSee);
    //dialog.run();
    std::cout << "I can't analyse this activity. Improve ActivityAnalysisDialog to load a full activity from its header (or add this feature to Activity object)\n";
}

///@brief Action when loading a SportTrack file
void TBmainWindow::on_menu_load_sporttrack()
{
    ///@warning This function is obsolete
    return;
    Gtk::FileChooserDialog dialog("Ouvrir..",
                                  Gtk::FILE_CHOOSER_ACTION_OPEN);
    dialog.set_transient_for(*this);

    //Add button to the dialog
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

    dialog.set_current_folder(Glib::get_home_dir());
    
    //Add filters
    Gtk::FileFilter filter_sportTrack;
    filter_sportTrack.set_name("Fichiers SportTrack v3");
    filter_sportTrack.add_pattern("*.logbook3");
    dialog.add_filter(filter_sportTrack);
    
    //Show the dialog
    int result = dialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            currentBook.ReadSportTrack3File(dialog.get_filename());
            update_treeview();
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}

///@brief Action when loading a fitlog file
void TBmainWindow::on_menu_load_fitlog()
{
    ///@warning This function is obsolete
    return;
    
    Gtk::FileChooserDialog dialog("Ouvrir..",
                                  Gtk::FILE_CHOOSER_ACTION_OPEN);
    dialog.set_transient_for(*this);
    
    //Add button to the dialog
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

    dialog.set_current_folder(Glib::get_home_dir());
    
    //Add filters
    Gtk::FileFilter filterFitlog;
    filterFitlog.set_name("Fichiers Fitlog");
    filterFitlog.add_pattern("*.fitlog");
    dialog.add_filter(filterFitlog);

    //Show the dialog
    int result = dialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            currentBook.ReadFitlogFile(dialog.get_filename());
            update_treeview();
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}

///@brief Action when loading a garmin file
void TBmainWindow::on_menu_load_garmin()
{
    Gtk::FileChooserDialog dialog("Ouvrir..",
                                  Gtk::FILE_CHOOSER_ACTION_OPEN);
    dialog.set_transient_for(*this);
    
    //Add button to the dialog
    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

    dialog.set_current_folder(Glib::get_home_dir());
    
    //Add filters
    Gtk::FileFilter filterGarmin;
    filterGarmin.set_name("Fichiers Garmin");
    filterGarmin.add_pattern("*.tcx");
    dialog.add_filter(filterGarmin);

    //Show the dialog
    int result = dialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            //currentBook.ReadGarminFile(dialog.get_filename());
            TcxImportDialog importDialog("Importer des activités...", this, dialog.get_filename());
            
            dialog.hide();
            int importResult = importDialog.run();
            switch(importResult)
            {
                case(Gtk::RESPONSE_OK):
                {
                    std::list<Activity> importedActivities = importDialog.DoTcxImport();
                    if(!importedActivities.empty())
                    {
                        for (std::list<Activity>::iterator iter = importedActivities.begin();
                             iter != importedActivities.end();
                             ++iter)
                        {
                            currentBook.AddActivity(*iter);
                        }
                    }
                    
                    break;
                }
                case(Gtk::RESPONSE_CANCEL):
                {
                    break;
                }
                default:
                {
                    break;
                }
            }
            
            
            
            update_treeview();
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
        {
            break;
        }
    }
}

///@brief Procedure that configure the menu of the main window
void TBmainWindow::ConfigureMenu()
{
    refActionGroup = Gtk::ActionGroup::create();

    //File menu
    refActionGroup->add(Gtk::Action::create("FileMenu", "Fichier"));
    refActionGroup->add(Gtk::Action::create("FileNew", Gtk::Stock::NEW));
    refActionGroup->add(Gtk::Action::create("FileNewActivity", "Nouvelle activité"),
                        sigc::mem_fun(*this, &TBmainWindow::on_menu_new_activity));
    refActionGroup->add(Gtk::Action::create("FileNewUserDay", "Nouvelle journée utilisateur"),
                        sigc::mem_fun(*this, &TBmainWindow::on_menu_new_user_day));
    refActionGroup->add(Gtk::Action::create("FileOpen", Gtk::Stock::OPEN),
                        sigc::mem_fun(*this, &TBmainWindow::on_menu_file_open));
    refActionGroup->add(Gtk::Action::create("LoadSportTrack", "Charger un fichier SportTrack v3"),
                        sigc::mem_fun(*this,&TBmainWindow::on_menu_load_sporttrack));
    refActionGroup->add(Gtk::Action::create("LoadFitLog", "Charger un fichier fitlog"),
                        sigc::mem_fun(*this, &TBmainWindow::on_menu_load_fitlog));
    refActionGroup->add(Gtk::Action::create("LoadGarmin", "Charger une activité Garmin"),
			sigc::mem_fun(*this, &TBmainWindow::on_menu_load_garmin));
    refActionGroup->add(Gtk::Action::create("FileSave", Gtk::Stock::SAVE),
                        sigc::mem_fun(*this, &TBmainWindow::on_menu_file_save));
    refActionGroup->add(Gtk::Action::create("FileSaveAs", Gtk::Stock::SAVE_AS),
                        sigc::mem_fun(*this, &TBmainWindow::on_menu_file_save_as));
    refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT),
                        sigc::mem_fun(*this, &TBmainWindow::on_button_quit));
    refActionGroup->add(Gtk::Action::create("EditMenu", "Édition"));
    refActionGroup->add(Gtk::Action::create("EditPrefs", "Préférences"),
                        sigc::mem_fun(*this, &TBmainWindow::on_prefs_click));
    refActionGroup->add(Gtk::Action::create("QuestionMenu", "?"));
    refActionGroup->add(Gtk::Action::create("About", "À propos de TrainingBook"),
                        sigc::mem_fun(*this, &TBmainWindow::on_about_click));


    refUIManager = Gtk::UIManager::create();
    refUIManager->insert_action_group(refActionGroup);

    Glib::ustring ui_info =
        "<ui>"
        "   <menubar name='MenuBar'>"
        "       <menu action='FileMenu'>"
        "           <menu action='FileNew'>"
        "               <menuitem action='FileNewActivity'/>"
        "               <menuitem action='FileNewUserDay' />"
        "           </menu>"
        "           <menuitem action='FileOpen'/>"
        //"           <menuitem action='LoadSportTrack'/>"
        //"           <menuitem action='LoadFitLog'/>"
        "           <menuitem action='LoadGarmin'/>"
        "           <menuitem action='FileSave'/>"
        "           <menuitem action='FileSaveAs'/>"
        "           <menuitem action='FileQuit'/>"
        "       </menu>"
        "       <menu action='EditMenu'>"
        "           <menuitem action='EditPrefs'/>"
        "       </menu>"
        "       <menu action='QuestionMenu'>"
        "           <menuitem action='About'/>"
        "       </menu>"
        "   </menubar>"
        "</ui>";

    try
    {
        refUIManager->add_ui_from_string(ui_info);
    }
    catch(const Glib::Error &ex)
    {
        std::cerr << "building menu failed: " << ex.what() << std::endl;
    }

    Gtk::Widget *pMenuBar = refUIManager->get_widget("/MenuBar");

    //Add widgets to the main VBox
    if(pMenuBar)
        mainVBox.pack_start(*pMenuBar, Gtk::PACK_SHRINK);

}

///@brief Refresh window
///@warning This function is a test. It should be improved (later ?)
void TBmainWindow::Refresh(const unsigned int&, const Glib::ustring& text)
{
    std::cout << text << "\n";
    statusBar.show_now();
}